package org.fujene.diskblock.repli;

import static org.fujene.diskblock.repli.ReplicateDictionaryDiskBlock.Type.*;

import java.io.File;
import java.io.UnsupportedEncodingException;

import org.fujene.diskblock.DiskBlock;
import org.fujene.memoryblock.MemoryBlock;
import org.fujene.memoryblock.repli.ReplicateDictionaryBlock;
import org.fujene.structure.Constants;
import org.fujene.structure.ExtendTerm;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;

public class ReplicateDictionaryDiskBlock extends DiskBlock {

	public ReplicateDictionaryDiskBlock(File fileDesc) throws Exception {
		super(fileDesc);
	}

	public ReplicateDictionaryDiskBlock(ReplicateDictionaryBlock memBlock, String dir) {
		super(memBlock, dir);
	}

	public enum Type {
		ALL, NEXT, DOCID, INVINDEX, STR, DOCFRQ,
	}

	private class DictionaryTerm {
		private LookupPointer nextTerm;
		private int docfreq;
		private LookupPointer[] invIndex;
		private long[] firstID;
		private int strlen;
		private String str;
		private int opt_type;

		// データ読み込み用
		public DictionaryTerm(int from, Type type) throws Exception {
			opt_type = getOption(1);

			if (type == ALL || type == NEXT)
				this.nextTerm = ByteConverter.getPtr(getBody(from, PTR));
			else
				this.nextTerm = Constants.emptyPointer;
			from += PTR;

			if (type == ALL || type == DOCFRQ)
				this.docfreq = ByteConverter.byteToInt(getBody(from, DOCFREQ));
			else
				this.nextTerm = Constants.emptyPointer;
			from += DOCFREQ;

			if (type == ALL || type == INVINDEX || type == DOCID) {
				this.invIndex = new LookupPointer[opt_type];
				this.firstID = new long[opt_type];
				for (int i = 0; i < opt_type; i++) {
					this.invIndex[i] = ByteConverter.getPtr(getBody(from, PTR));
					from += PTR;
					this.firstID[i] = ByteConverter
							.byteToLong(getBody(from, 8));
					from += 8;
				}
			}

			if (type == ALL || type == STR) {
				this.strlen = ByteConverter.byteToInt(getBody(from, STRLEN));
				from += STRLEN;
				try {
					this.str = new String(getBody(from, strlen), "UTF-8");
				} catch (UnsupportedEncodingException e) {
				}
			}
		}
	}

	public LookupPointer getDocIDPointer(int index, int ptr) throws Exception {
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, Type.DOCID);

		if (ptredDic.invIndex[index].equals(Constants.emptyPointer))
			return null;
		else
			return ptredDic.invIndex[index];
	}

	public long getFirstPointer(int index, int ptr) throws Exception {
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, Type.DOCID);

		return ptredDic.firstID[index];
	}

	// 情報読み込み
	public ExtendTerm getTerm(int ptr, int indexType) throws Exception {
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, ALL);

		if (ptredDic.nextTerm.equals(Constants.emptyPointer))
			ptredDic.nextTerm = null;
		if (ptredDic.invIndex[indexType].equals(Constants.emptyPointer))
			ptredDic.invIndex[indexType] = null;

		return new ExtendTerm(ptredDic.str, ptredDic.nextTerm, null, new LookupPointer(this.getID(), ptr), -1,
				ptredDic.invIndex, ptredDic.firstID, ptredDic.docfreq);
	}

	public int getTermCount() throws Exception {
		return this.getOption(0);
	}

	public LookupPointer getNextPointer(int ptr) throws Exception {
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, NEXT);

		if (ptredDic.nextTerm.equals(Constants.emptyPointer))
			return null;
		else
			return ptredDic.nextTerm;
	}

	public LookupPointer getInvIndexPointer(int ptr, int index)
			throws Exception {
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, INVINDEX);

		if (ptredDic.invIndex[index].equals(Constants.emptyPointer))
			return null;
		else {
			LookupPointer retPtr = ptredDic.invIndex[index];
			retPtr.firstID = ptredDic.firstID[index];
			return ptredDic.invIndex[index];
		}
	}

	public long getFirstID(int ptr, int index) throws Exception {
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, DOCID);

		return ptredDic.firstID[index];
	}

	@Override
	public void readToMemory(MemoryBlock memBlock) {
		if (memBlock instanceof ReplicateDictionaryBlock) {
			try {
				memBlock.setOption(0, this.getOption(0));
				memBlock.setBody(this.getBody(0, this.bodySize), 0);
				memBlock.setBodyVacancy(this.bodyVacancy);
			} catch (Exception e) {
			}
		}
	}

	@Override
	public byte[] getData() {
		throw new NoSuchMethodError("Unimplemented method");
	}
}
